Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build without swift host tools #77815

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

DougGregor
Copy link
Member

Introduce various fixes to the build system, compiler, and standard library to enable building without Swift host tools, to make it possible to bootstrap a Swift compiler on a host that does not have Swift yet (without cross-compiling). The compiler built from only C++ doesn't need to have full functionality (and it doesn't---at least macros and embedded won't work), but it needs to have enough functionality to act as host tools for a full build of the toolchain.

@DougGregor
Copy link
Member Author

The preset comes from #77795

@DougGregor
Copy link
Member Author

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

1 similar comment
@DougGregor
Copy link
Member Author

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

@DougGregor DougGregor force-pushed the build-without-swift-host-tools branch from 8c53569 to e333144 Compare November 23, 2024 00:29
@DougGregor
Copy link
Member Author

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

@DougGregor
Copy link
Member Author

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

@DougGregor
Copy link
Member Author

Next failure is...

Begin Error in Function: '$sSysE15_toUTF16IndicesySnySS5IndexVGSnySiGFSS_Tg5'
Found an operand with a value that is not compatible with the operand's operand ownership kind map.
Value:   %181 = unchecked_bitwise_cast %177 : $String to $Substring // user: %182
Value Ownership Kind: unowned
Instruction:
     %181 = unchecked_bitwise_cast %177 : $String to $Substring // user: %182
->   %182 = begin_borrow %181 : $Substring
Constraint: <Constraint Kind:any LifetimeConstraint:NonLifetimeEnding>
End Error in Function: '$sSysE15_toUTF16IndicesySnySS5IndexVGSnySiGFSS_Tg5'
Found ownership error?!

@DougGregor
Copy link
Member Author

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

@DougGregor
Copy link
Member Author

Trying something hideous, unless @eeckstein has any better ideas for the last failure?

@finagolfin
Copy link
Member

Is this just an experiment to see how far you get or do you really expect to get bootstrapping to work again? It's been a year since the CI switched over to only using a prebuilt Swift 5.8.1 compiler to build the trunk compiler, so I doubt you can get all those dependencies weeded out again.

Even if you get a basic bootstrap C++-only compiler built again, it may no longer work to build the full compiler with swift-syntax. For example, I just successfully cross-compiled the trunk compiler for Android for the first time in nine months, and I initially tried working around a recent swift-driver issue on Unix platforms by disabling it and going back to the legacy C++ Driver. However, that would get the same tag of the prebuilt official linux toolchain for Fedora that I was using to cross-compile swift-syntax to hang, pegging a CPU core in my Fedora x86_64 virtual server for half an hour each time till I think the host kept killing it.

Only once I put in another workaround for the swift-driver issue and went back to swift-driver did that finally cross-compile, implying the swift-syntax build now depends on some new swift-driver flags that aren't in the legacy C++ Driver anymore, which is all you'll have in this bootstrap compiler too.

Rather than fixing potentially dozens of bootstrap issues like this, I think it would be better to rip out the last remaining bootstrap support and make it easier to cross-compile and test the Swift stdlib and compiler for new platforms, which after all you've been warning people is the plan now for years on the forum.

@DougGregor
Copy link
Member Author

Is this just an experiment to see how far you get or do you really expect to get bootstrapping to work again? It's been a year since the CI switched over to only using a prebuilt Swift 5.8.1 compiler to build the trunk compiler, so I doubt you can get all those dependencies weeded out again.

I'm trying to see whether we can build enough of a toolchain from just the C++ code to serve as a host toolchain to build the full compiler.

Even if you get a basic bootstrap C++-only compiler built again, it may no longer work to build the full compiler with swift-syntax.

To be clear, I don't want to do the bootstrapping mode ever again. It's "use C++ to build a minimal host toolchain, use that as host tools to build the full compiler." If it doesn't work, fine, If it does work, we should consider keeping that around until...

make it easier to cross-compile and test the Swift stdlib and compiler for new platforms, which after all you've been warning people is the plan now for years on the forum.

Yes, that's the goal. We're not at that goal, and are in an unfortunate place where both paths are hard. I'm trying to determine whether we can resurrect the starting-from-C++ path and keep it around a little longer to bridge the gap until cross-compilation becomes easier.

@DougGregor
Copy link
Member Author

Okay, we timed out in testing, so... that's an improvement?

@DougGregor
Copy link
Member Author

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

1 similar comment
@compnerd
Copy link
Member

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

@eeckstein
Copy link
Contributor

We should also disable optimizations for bootstrapping because more optimizer utilities are implemented in swift and used from C++ passes:

diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp
index 3057d6cf458..c6956f2faff 100644
--- a/lib/Frontend/CompilerInvocation.cpp
+++ b/lib/Frontend/CompilerInvocation.cpp
@@ -2585,7 +2585,10 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
   // Default to Onone settings if no option is passed.
   Opts.OptMode = OptimizationMode::NoOptimization;
   if (const Arg *A = Args.getLastArg(OPT_O_Group)) {
-    if (A->getOption().matches(OPT_Onone)) {
+    if (A->getOption().matches(OPT_Onone) ||
+        // For the purpose of bootstrapping disable optimizations because C++
+        // implemented optimizations can depend on Swift-implemented utilities.
+        !swiftModulesInitialized()) {
       // Already set.
     } else if (A->getOption().matches(OPT_Ounchecked)) {
       // Turn on optimizations and remove all runtime checks.

@compnerd
Copy link
Member

preset=buildbot_linux,without_host_swift
@swift-ci Please test with preset Linux Platform

@compnerd
Copy link
Member

We should also disable optimizations for bootstrapping because more optimizer utilities are implemented in swift and used from C++ passes:

I wonder if we should hardcode this into the compiler or into the build system. I feel like the build system might be a better place to encode this by ensuring that if we are building the stage0 compiler we always build with -Onone explicitly.

@etcwilde and @justice-adams-apple might have thoughts on this though.

@compnerd
Copy link
Member

Cancelling nested steps due to timeout

Pretty sure that the bootstrapped toolchain is hanging in the test suite somewhere.

@DougGregor
Copy link
Member Author

Pretty sure that the bootstrapped toolchain is hanging in the test suite somewhere.

Yeah, the answer to which might very well be... don't build the test suite. We don't need the test suite to work, really; we need enough to build the next phase. Aside from the preset, the rest of these commits are probably good to land, then we can figure out how to chop away the bits we don't need to get to a minimal toolchain.

@@ -956,6 +956,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows" AND CMAKE_SYSTEM_PROCESSOR MATCHES "ARM6
set(BOOTSTRAPPING_MODE "OFF")
endif()

# Disable bootstrapping when we aren't building SwiftSyntax
if(NOT SWIFT_BUILD_SWIFT_SYNTAX)
Copy link
Contributor

@eeckstein eeckstein Dec 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do that in a safer way? I'm afraid that this can lead to accidentally disabling SwiftCompilerSources in a shipped release-compiler (e.g. by someone removing swift-syntax from a build-preset). This could get mostly unnoticed because it only affects optimizations, i.e. the qualify of generated code.

E.g. by excluding platforms which we expect to have hosttools (macos, linux, windows).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd expect it to go in the other direction. Fully bring back the BOOTSTRAPPING_MODE "OFF" as an option, then if bootstrapping=off we also disable the other parts that depend on Swift. Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A released compiler without swift-syntax wouldn't support macros, so I don't think it can happen accidentally. That said, my if(NOT SWIFT_BUILD_SWIFT_SYNTAX) hack is awful. I'm all for bringing back BOOTSTRAPPING_MODE "OFF" to make this explicit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! It turns out that we don't specifically need either my hack or BOOTSTRAPPING_MODE "OFF", since we still have the code that disables SwiftCompilerSources when there is no Swift toolchain, here: https://github.com/swiftlang/swift/blob/main/CMakeLists.txt#L966

I'm going to remove this commit entirely for now, and we can (independently) decide whether to bring back an easier way to turn off bootstrapping and ignore any host Swift toolchain. For now, we'll test this in an environment where there is no swift toolchain.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I'm going to refute my own comment 2 hours later. I went ahead and reverted the change that dropped bootstrapping=off support so we can more easily turn off bootstrapping locally for testing. I'm still trying to bring this up in a container with no host Swift just to be sure (and that's probably how we would want to configure CI).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd expect it to go in the other direction. Fully bring back the BOOTSTRAPPING_MODE "OFF" as an option

No. I intentionally made it to not be turned off because people disabled it in their local development and wondered why some things are not working in the compiler.
SwiftCompilerSources are mandatory, except for the purpose of bootstrapping the compiler on new platforms.

@DougGregor DougGregor force-pushed the build-without-swift-host-tools branch from 005862c to e85e680 Compare December 5, 2024 00:09
@DougGregor
Copy link
Member Author

swiftlang/swift-foundation#1071

preset=minimal_toolchain_without_host_swift
@swift-ci Please test with preset Linux Platform

@DougGregor
Copy link
Member Author

DougGregor commented Dec 5, 2024

The Foundation PR (minimal_toolchain_without_host_swift) is needed to get swift-foundation building with the C++-only Swift compiler

@DougGregor
Copy link
Member Author

@swift-ci please test

@DougGregor
Copy link
Member Author

... checking to see if I broke anything in the normal build.

if (NOT BOOTSTRAPPING_MODE)
message(FATAL_ERROR "turning off bootstrapping is not supported anymore")
endif()

Copy link
Contributor

@eeckstein eeckstein Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm against removing this check.

We should only allow turning off BOOTSTRAPPING in the very specific case of cross compilation.

IMO, the risk is too high that someone accidentally turns it off and it gets unnoticed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving it as a default to hosttools is fine. The compiler itself still needs to produce valid output with swift sources disabled, even if it is less optimized. Given that the off-mode also disables macro support, it seems likely that it will be noticed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that the off-mode also disables macro support

Does it? The BOOTSTRAPPING Cmake flag only impacts SwiftCompilerSources, AFAIK.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about letting the compiler print a warning if SwiftCompilerSources are disabled?

Copy link
Contributor

@eeckstein eeckstein Dec 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler itself still needs to produce valid output with swift sources disabled

Sure, but there shouldn't be another motivation to disable SwiftCompilerSources than for cross-compiling where no host-tools are available. And for that case we already do this in the cmake file:

set(SWIFT_EXEC_FOR_SWIFT_MODULES "${CMAKE_Swift_COMPILER}")
  if(NOT SWIFT_EXEC_FOR_SWIFT_MODULES)
    message(WARNING "BOOTSTRAPPING set to OFF because no Swift compiler is defined")
    set(BOOTSTRAPPING_MODE "OFF")
  endif()

Therefore I don't understand why we have to remove this check

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now, there are different flags controlling disabling swift-syntax in the compiler (which drops macros support, among other things) vs. disabling SwiftCompilerSources in the compiler (which drops embedded support and breaks no-locks/no-allocation checking, among other optimizer effects).

I'm a bit dubious on the notion that we have to work hard to prevent people from using bootstrapping=off and being surprised. If it really is that important to prevent misconfigurations, we could create a new CMake + build-script option for this "minimal C++-only build" that disables both of those at once. Checking SWIFT_EXEC_FOR_SWIFT_MODULES isn't that great, because it doesn't let you build this configuration if there's a Swift in your path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it would be good to have a single flag which turns off everything (macros, swiftcompilersource, etc.). This would make accidental misconfiguration very unlikely. Plus a compiler warning as a bonus.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I've added build-script --minimal-cxx-bootstrap to do this, which maps down to the CMake option SWIFT_MINIMAL_CXX_BOOTSTRAP and centralizes most of the logic for turning off stuff in the build.

@DougGregor DougGregor force-pushed the build-without-swift-host-tools branch from e85e680 to 0156d57 Compare December 6, 2024 23:12
@DougGregor
Copy link
Member Author

preset=minimal_toolchain_without_host_swift
@swift-ci Please test with preset Linux Platform

@DougGregor DougGregor force-pushed the build-without-swift-host-tools branch from 0156d57 to 68541b2 Compare December 7, 2024 00:26
@DougGregor
Copy link
Member Author

preset=minimal_toolchain_without_host_swift
@swift-ci Please test with preset Linux Platform

CMakeLists.txt Outdated
set(SWIFT_BUILD_REGEX_PARSER_IN_COMPILER OFF)

# Disable string processing library
set(SWIFT_ENABLE_EXPERIMENTAL_STRING_PROCESSING OFF)
Copy link
Contributor

@3405691582 3405691582 Jan 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Foundation seems to need string processing and the regex parser available to build. Of course, one can turn these back on with extra-cmake-options but that seems roundabout.

On the other hand, perhaps Foundation needs to change to avoid these features? That may require more care than is warranted when writing Foundation code, which may not be desirable.

…swift-syntax

When building without swift-syntax, we don't have the ability to handle
macros. However, the concurrency runtime makes use of `#isolation` in
a number of places. To continue supporting building without
swift-syntax, parse `#isolation` directly into the otherwise-unspellable
CurrentContextIsolationExpr but *only* when swift-syntax is not available.
Based on a patch from Evan Wilde, introduce a new preset that disables
the features that require Swift host tools. This involves disabling
early swift-syntax (used in the compiler for macros et al) and early
swift-driver.
These annotations require optimization passes that are written in
Swift, so we need a host Swift compiler to properly process them. Use
`hasFeature(Macros)` as a way to gate the annotations.
@DougGregor DougGregor force-pushed the build-without-swift-host-tools branch from 68541b2 to 04ce3fe Compare February 15, 2025 06:06
@DougGregor
Copy link
Member Author

@swift-ci please test

@@ -943,6 +943,13 @@ if (NOT BOOTSTRAPPING_MODE)
message(FATAL_ERROR "turning off bootstrapping is not supported anymore")
endif()

endif()

# Disable bootstrapping when we aren't building SwiftSyntax
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is not very helpful - it just describes what one can read from the next two source lines, anyway.

Can you add more context here? I assume that SWIFT_BUILD_SWIFT_SYNTAX is the main "switch" which tells if host tools are available.
If so, why not call it SWIFT_HOST_TOOLS_AVAILABLE or something like that. It feels like SWIFT_BUILD_SWIFT_SYNTAX is abused for that purpose.

@3405691582
Copy link
Contributor

3405691582 commented Feb 17, 2025

As a heads-up, #79186 migrated a key function pass to Swift. This pass has the side effect of deleting unreachable instructions at the end of infinite loops. When the build process bootstraps the stdlib with -parse-stdlib, that pass doesn't run (because it can't be built yet) , which means those unreachable instructions continue through the pipeline and trip "missing return" errors in the diagnostic passes, manifesting as "missing return" errors. This doesn't happen when Swift host tools are present, since either the Swift pass runs because they're part of the host tools, and/or when host tools are present, the -parse-stdlib phase doesn't need to happen.

The simplest, easiest, and fastest thing to fix this might be to inject some synthetic return statements into the relevant parts of the stdlib so those unreachable instructions don't occur, but the right thing to do might be to create a C++ pass to try and identify infinite loops containing returns and edit them to remove any unreachables -- I don't know if that's actually possible, I've only stared at this for a few days.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants